<?php 

namespace common\help;
/**
 * +----------------------------------------------------------------------
 * | 文件上传类 Author Ftd Date: 15-03-18
 * | 如果上传的文件是图片类型，提供生成缩略图方法
 * +----------------------------------------------------------------------
 * | 主要方法:upload();createThumb();
 * +----------------------------------------------------------------------
 * | 使用方法: 创建一个config = array();
 * | 提供参数：
 *   savePath       string              可选 文件上传路径(若为空则为当前目录下的upload文件夹) 
 *   thumbSavePath  string              可选 缩略图上传路径(若为空则代表和savePath相同的路径)                
 *   ext            string(逗号分割)    可选 允许上传的文件类型(若为空则代表允许上传任何类型的文件)
 *   maxSize        int                 可选 允许上传的最大值(若为空或为0则表示无限大)，此处和php.ini配置文件无关
 *   fileName       string              可选 上传文件名(若为空则使用源文件名)
 *   needThumb      bool                可选 是否需要生成缩略图
 *   thumbWidth     int                 可选 缩略图宽度(若needThumb为true,则为必需)
 *   thumbHeight    int                 可选 缩略图高度(若needThumb为true,则为必需)
 *   needReplcePic  bool                可选 是否覆盖源文件(若为空则表示不覆盖，若savePath不等于thumbSavePath,此参数失效)
 * +----------------------------------------------------------------------
 * | 举例：
 * 
 *    $config = array(     //设置配置参数
 *       key => value
 *    )
 *    $obj = new UploadFile($config); //实例化对象
 *    $obj->upload($_FILES); //上传文件
 *    $obj->createThumb(); //生成缩略图
 * +----------------------------------------------------------------------
 * 
 */ 

class UploadFile 
{
    private $savePath ;  //上传路径
    private $ext = array(); //允许的后缀名，为空则表示不限制
    private $fileName ; //文件名
    private $fileTempName;//临时文件名
    private $maxSize; //允许上传最大值

    private $fileExt;//文件后缀名
    private $fileSize;//文件大小

    private $errorNum; //错误号
    private $errorMsg = ''; //错误信息


    private $srcFile; //源文件，用来生成缩略图
    private $thumbFile;//缩略图文件
    private $thumbSavePath;//缩略图上传路径
    private $tempThumbImg;//临时缩略图
    private $thumbWidth;  //缩略图宽度
    private $thumbHeight; //缩略图高度
    private $needThumb;      //是否需要缩略图
    private $needReplcePic;//是否覆盖源文件

    //默认配置
    private $acquiesce_config = array(
        'savePath' => './upload/',
        'thumbSavePath' => '',
        'ext' => '',
        'maxSize' => 0,
        'fileName' => '',
        'needThumb' => false,
        'thumbWidth' => 0,
        'thumbHeight' => 0,
        'needReplcePic' => false
    );

    /**
     * 构造方法
     * @param [array] $config
     */
    public function __construct($config = array())
    {   
        //如果参数为完全设置，将其设置为默认参数
        $config = array_merge($this->acquiesce_config,$config);
        $this->set_config($config);
    }

    /**
     * 设置上传配置
     * @param [array] $config 
     */
    private function set_config($config)
    {   
        //分割字符串得到文件允许后缀名
        $ext_arr = explode(',', $config['ext']); 
        foreach ($ext_arr as $k => $v) {
            if($v != '')
            {
                $this->ext[] = $v;
            }
        }
        $this->set('savePath',$config['savePath']);
        $this->set('maxSize',$config['maxSize']);
        $this->set('fileName',$config['fileName']);

        $this->set('thumbHeight',$config['thumbHeight']);
        $this->set('thumbWidth',$config['thumbWidth']);
        $this->set('needThumb',$config['needThumb']);
        $this->set('needReplcePic',$config['needReplcePic']); 
        $this->thumbSavePath = $config['thumbSavePath'] == '' ? $this->savePath : $config['thumbSavePath'];
    }

    /**
     * [上传文件]
     * @param  [$file($_FILES)] 
     * @return [true|false]
     */
    public function upload($file,$save_path,$file_name)
    {
        if(!empty($file))
        {
            $fileName = $file['file']['name'];
            $fileSize = $file['file']['size'];
            $fileTempName = $file['file']['tmp_name'];
            $errorNum = $file['file']['error'];
            $ext = $this->get_fileExt($fileName);
            //检查文件参数
            $flag = $this->check_file_and_config($fileSize,$ext,$errorNum);
            if(!$flag)
            {
                // return $this->get_errorMsg();
                return false;
            }
            //设置文件名
            if($this->fileName != null)
            {
                $fileName = $this->fileName .'.'. $ext;
            }
            //设置文件属性
            $this->set_file($fileName,$fileTempName,$fileSize,$ext);
            //移动(上传)文件
            if(!$this->move_file())
            {
                // return $this->get_errorMsg();
                return false;
            }
            return $save_path."/".$file_name.".".$ext;
        }
    }


    /**
     * 得到文件后缀名
     * @param  [string] $fileName [文件名]
     * @return [string]            [文件后缀名]
     */
    private function get_fileExt($fileName)
    {   
        //得到文件最后一个小数点，如果为false，说明文件没有后缀名
        $is_has_ext = strripos($fileName, '.');
        if(false == $is_has_ext)
        {
            return '';
        }
        $file_arr = explode('.', $fileName);
        $fileExt = strtolower($file_arr[count($file_arr) - 1]);
        return $fileExt;
    }

    /**
     * 检查文件的合法性
     * @param  [int]  $fileSize [文件大小]
     * @param  [string]  $ext       [文件后缀名]
     * @param  integer $errorNum [错误编号]
     * @return [true|false]            
     */
    private function check_file_and_config($fileSize,$ext,$errorNum = 0)
    {   

        $this->set('errorNum',$errorNum);

        if($errorNum != 0)
        {   
            return false;
        }
        if($this->savePath == '')
        {
            $this->set('errorNum',7);
            return false;
        }
        if(!in_array($ext, $this->ext) && count($this->ext) != 0)
        {
            $this->set('errorNum',5);
            return false;
        }
        if($fileSize > $this->maxSize && $this->maxSize != 0 && $this->maxSize != null)
        {
            $this->set('errorNum',6);
            return false;
        }

        return true;
    }

    /**
     * [设置成员变量]
     * @param [string] $fileName      [文件名]
     * @param [string] $fileTempName [临时文件名]
     * @param [int] $fileSize      [文件大小]
     * @param [string] $ext            [文件后缀名]
     */
    private function set_file($fileName,$fileTempName,$fileSize,$ext)
    {
        $this->set('fileName',$fileName);
        $this->set('fileTempName',$fileTempName);
        $this->set('fileSize',$fileSize);
        $this->set('fileExt',$ext);
    }


    /**
     * [移动文件]
     * @return [true|false] [成功返回true]
     */
    private function move_file()
    {   
        if($this->errorNum == 0)
        {   
            //创建文件上传目录
            $this->create_folders($this->savePath);
            $move_file = $this->savePath .'/'. $this->fileName;
            if(move_uploaded_file($this->fileTempName, $move_file))
            {   
                //设置源文件,用来创建缩略图
                $this->srcFile = $move_file;
                return true;
            }else
            {
                $this->set('errorNum',8);
                return false;
            }
        }else{
            return false;
        }
    }

    /**
     * [生成缩略图]
     * @return [string] 
     */
    public function createThumb()
    {   
        $flag = $this->check_thumb_param();
        if(!$flag)
        {   
            return $this->get_errorMsg();
        }
        $this->build_temp_thumb_img();//创建临时图片
        $this->build_thumb_path(); //创建缩略图路径
        if(!$this->build_thumb())
        {
            return $this->get_errorMsg();
        }
        return 'create_thumb_success';
    }

    /**
     * [创建缩略图]
     * @return [true|false] 
     */
    private function build_thumb()
    {   
        //根据不同后缀名得到不同的方法
        $image_create_method = $this->get_create_img_function();
        //图片实际宽度
        $real_width = imagesx($this->tempThumbImg);
        //图片实际高度
        $real_height = imagesy($this->tempThumbImg);

        $thumb_img = imagecreatetruecolor($this->thumbWidth, $this->thumbHeight);
        $flag = imagecopyresampled($thumb_img, $this->tempThumbImg, 0, 0, 0, 0, $this->thumbWidth, $this->thumbHeight, $real_width, $real_height);
        $image_create_method($thumb_img,$this->thumbFile);
        if(!$flag)
        {
            $this->set('errorNum',13);
            return false;
        }
        return true;
    }

    /**
     * [得到imagejpeg|imagegif|imagepng]
     * @return [string] [方法名]
     */
    private function get_create_img_function()
    {
        if($this->fileExt == 'jpg')
        {
            $method = 'image'.'jpeg';
            return $method;
        }
        $method = 'image'.strtolower($this->fileExt);
        return $method;
    }

    /**
     * [检查缩略图文件参数]
     * @return [true|false] 
     */
    private function check_thumb_param()
    {   

        if($this->errorNum != 0)
        {
            return false;
        }
        if(empty($this->srcFile))
        {
            $this->set('errorNum',9);
            return false;
        }
        if($this->fileExt != 'jpg' && $this->fileExt != 'gif' && $this->fileExt != 'png')
        {
            $this->set('errorNum',10);
            return false;
        }
        if(!$this->needThumb)
        {
            $this->set('errorNum',11);
            return false;
        }
        if($this->thumbWidth == 0 || $this->thumbHeight == 0 || $this->thumbWidth == '' || $this->thumbHeight == '')
        {
            $this->set('errorNum',12);
            return false;
        }
        return true;
    }

    /**
     * [创建缩略图路径]
     * @return [null] 
     */
    private function build_thumb_path()
    {   

        if($this->savePath == $this->thumbSavePath)
        {
            if($this->needReplcePic)
            {
                $this->thumbFile = $this->srcFile;
            }else
            {
                $this->thumbFile = $this->savePath.'/'.'thumb-'.$this->fileName;
            }

        }else{
            $this->create_folders($this->thumbSavePath);
            $this->thumbFile = $this->thumbSavePath.'/'.$this->fileName;
        }

    }

    /**
     * [创建临时图片]
     * @return [null]
     */
    private function build_temp_thumb_img()
    {
        switch ($this->fileExt) {
            case 'jpg':
                $this->set('tempThumbImg',imagecreatefromjpeg($this->srcFile));
                break;
            case 'gif':
                $this->set('tempThumbImg',imagecreatefromgif($this->srcFile));
                break;
            case 'png':
                $this->set('tempThumbImg',imagecreatefrompng($this->srcFile));
                break;  
            default:
                break;
        }
    }


    /**
     * 返回错误信息
     * @return [string] 
     */
    private function get_errorMsg()
    {
        switch ($this->errorNum) {
            case 13:
                $this->errorMsg = "生成缩略图失败";
                break;
            case 12:
                $this->errorMsg = "错误的缩率图高度或宽度";
                break;
            case 11:
                $this->errorMsg = "若要生成缩略图，请在config中设置needThumb为true";
                break;
            case 10:
                $this->errorMsg = "该文件不是图片类型，不能产生缩略图";
                break;
            case 9:
                $this->errorMsg = "源文件不存在，无法生成缩略图，请先上传文件";
                break;
            case 8:
                $this->errorMsg = "上传失败";
                break;
            case 7:
                $this->errorMsg = '请设置上传路径';
                break;
            case 6:
                $this->errorMsg = '上传文件大小超过maxSize最大值';
                break;
            case 5:
                $this->errorMsg = "错误的文件类型";
                break;
            case 4:
                $this->errorMsg = '没有文件被上传';
                break;
            case 3:
                $this->errorMsg = '文件只有部分被上传';
                break;
            case 2:
                $this->errorMsg = '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值';
                break;      
            case 1:
                $this->errorMsg = '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值';
                break;
            default:
                break;
        }

        return $this->errorMsg;
    }

    /**
     * set方法(过滤成员参数)
     * @param  $key   
     * @param  $value 
     */
    public function set($key,$value)
    {   
        //检验key是否是本类的成员属性
        if(array_key_exists($key, get_class_vars(get_class($this))))
        {
            $this->setProperty($key,$value);
        }
    }

    /**
     * [设置property]
     * @param [property] $key  
     * @param [property] $value 
     */
    private function setProperty($key,$value)
    {   
        if($key == 'ext')
        {
            $ext_arr = explode(',', $value);
            foreach ($ext_arr as $k => $v) {
                if($v != '')
                {
                    $this->ext[] = $v;
                }
            }
            return;
        }
        $this->$key = $value;
    }

    /**
     * 递归创建文件夹
     * @param  [string] $dir [目录]
     * @return [true|false]     
     */
    private function create_folders($dir)
    {
        return is_dir($dir) or ($this->create_folders(dirname($dir)) and mkdir($dir, 0777));
    }
}

 ?>